#include "gene.h"
//#include "contig.h"
#include "genomesegment.h"
#include "infobox.h"
#include "../../DataStorageClasses/qualitativeattribute.h"

Gene::Gene(QString gId, int sta, int sto, bool ip, GenomeSegment *p) ://Contig *p) :
    QGraphicsWidget(p)
{
    geneId = gId;
    start = sta;
    stop = sto;
    //ip = isPosStrand;//GAH WHAT A HORRIBLE MISTAKE
    isPosStrand = ip;

    unselectedColor = new QColor( 147.0, 215.0, 255.0 );
    highlightedColor = new QColor( 255.0, 242.0, 42.0 );
    //highlightedColor = new QColor( 255.0, 255.0, 255.0, 255.0 );//255.0, 242.0, 42.0, 150.0 );


    geneInfo = new InfoBox( 2, geneId, this );//dir, text, parent
    geneInfo->setPos( boundingRect().x() + (boundingRect().x()+boundingRect().width())/2.0, boundingRect().y() );
    geneInfo->setVisible(false);

    setAcceptsHoverEvents(true);
    hovering = false;
    selected = false;
    this->setAcceptedMouseButtons(Qt::LeftButton);
    this->setFlag(QGraphicsItem::ItemIsSelectable);
    setCursor( Qt::ArrowCursor );//make sure arrow cursor is show over gene

    parent = p;

    //setVisible( true );
    setAttribute(Qt::WA_OpaquePaintEvent,true);

    userGivenColor = new QColor( 0, 0, 0, 0);
    colorToDraw = new QColor( 0, 0, 0, 0);
    backgroundColor = new QColor( parent->backgroundColor.red(), parent->backgroundColor.green(), parent->backgroundColor.blue(), parent->backgroundColor.alpha() )  ;

    setFlag( QGraphicsItem::ItemIsFocusable );//needed for keypress event
    alignKeyPressed = false;
    flipKeyPressed = false;
    colorKeyPressed = false;

    //test of coloring
//    if( geneId.contains( "gene16") )
//    {
//        userGivenColor->setRgb(244.0f, 42.0f, 122.0f, 255.0f);
//    }
//    else if( geneId.contains( "gene2"))
//    {
//        userGivenColor->setRgb(192.0, 0.0, 239.0, 255.0) ;
//    }
//    else if( geneId.contains( "gene3"))
//    {
//        userGivenColor->setRgb(224.0, 122.0, 59.0, 255.0);
//    }



    if( geneId.contains( "gene16") )
    {
        userGivenColor->setRgb(244.0, 42.0, 122.0, 255.0);
    }
    else if( geneId.contains( "gene22"))
    {
        userGivenColor->setRgb( 192.0, 0.0, 239.0, 255.0) ;
    }
    else if( geneId.contains( "gene34"))
    {
        userGivenColor->setRgb(224.0, 122.0, 59.0, 255.0);
    }
    else if( geneId.contains( "gene11"))
    {
        userGivenColor->setRgb( 78.0, 224.0, 139.0, 255.0);
    }
    else if( geneId.contains( "gene5"))
    {
        userGivenColor->setRgb( 96.0, 69.0, 249.0, 255.0);
    }
    else if( geneId.contains( "gene29"))
    {
        userGivenColor->setRgb( 18.0, 161.0, 54.0, 255.0);
    }
    else if( geneId.contains( "gene40"))
    {
        userGivenColor->setRgb( 96.0, 69.0, 249.0, 255.0);
    }
    if( geneId.contains( "gene12") )
    {
        userGivenColor->setRgb(244.0, 42.0, 122.0, 255.0);
    }
    else if( geneId.contains( "gene23"))
    {
        userGivenColor->setRgb( 192.0, 0.0, 239.0, 255.0) ;
    }
    else if( geneId.contains( "gene24"))
    {
        userGivenColor->setRgb(224.0, 122.0, 59.0, 255.0);
    }
    else if( geneId.contains( "gene55"))
    {
        userGivenColor->setRgb( 78.0, 224.0, 139.0, 255.0);
    }
    else if( geneId.contains( "gene36"))
    {
        userGivenColor->setRgb( 96.0, 69.0, 249.0, 255.0);
    }
    else if( geneId.contains( "gene27"))
    {
        userGivenColor->setRgb( 18.0, 161.0, 54.0, 255.0);
    }
    else if( geneId.contains( "gene7"))
    {
        userGivenColor->setRgb( 96.0, 69.0, 249.0, 255.0);
    }


    else if( geneId.compare( "Cluster10", Qt::CaseInsensitive ) == 0 )
    {
        userGivenColor->setRgb(244.0, 42.0, 122.0, 255.0);
    }
    else if( geneId.compare( "Cluster61", Qt::CaseInsensitive ) == 0 )
    {
        userGivenColor->setRgb( 192.0, 0.0, 239.0, 255.0) ;
    }
    else if( geneId.compare( "Cluster7", Qt::CaseInsensitive ) == 0 )
    {
        userGivenColor->setRgb(224.0, 122.0, 59.0, 255.0);
    }
    else if( geneId.compare( "Cluster58", Qt::CaseInsensitive ) == 0 )
    {
        userGivenColor->setRgb( 78.0, 224.0, 139.0, 255.0);
    }
    else if( geneId.compare( "Cluster26", Qt::CaseInsensitive ) == 0 )
    {
        userGivenColor->setRgb( 96.0, 69.0, 249.0, 255.0);
    }
    else if( geneId.compare( "Cluster64", Qt::CaseInsensitive ) == 0 )
    {
        userGivenColor->setRgb( 18.0, 161.0, 54.0, 255.0);
    }

    else
    {
        userGivenColor->setRgb( unselectedColor->red(), unselectedColor->green(), unselectedColor->blue(), unselectedColor->alpha() );
    }

    colorToDraw->setRgb(userGivenColor->red(), userGivenColor->green(), userGivenColor->blue(), userGivenColor->alpha() );

    setCacheMode(QGraphicsItem::ItemCoordinateCache);//this call is magic- render to pixmap makes it faster
}

Gene::~Gene()
{
    if( geneInfo != NULL )
        delete geneInfo;

    if( unselectedColor  != NULL )
        delete unselectedColor;

    if( highlightedColor != NULL )
        delete highlightedColor;

    if( userGivenColor != NULL )
        delete userGivenColor;

    if( colorToDraw  != NULL )
        delete colorToDraw;

    if( backgroundColor  != NULL )
        delete backgroundColor;

    qDeleteAll( attributes );
}

void Gene::addAttribute( QString attribute, QString attributeName )
{
    //qDebug() << "       add attribute " << attribute << "   " << attributeName << endl;
    attributes << new QualitativeAttribute( attribute, attributeName ); //note- right now this attribute does nothing
    geneInfo->addLineOfText( attributeName.append(":  ").append( attribute ));
}

void Gene::addAttribute( QString attribute, QString attributeName, QList<float> confidenceMetric, QList<QString> confidenceMetricLabel )
{
    //qDebug() << "       add attribute " << attribute << "   " << attributeName << endl;
    attributes << new QualitativeAttribute( attribute, attributeName );
    geneInfo->addLineOfText( attributeName.append(":  ").append( attribute ));
}


int Gene::getStart()
{
    return start;
}

int Gene::getStop()
{
    return stop;
}

QString Gene::getGeneId()
{
    return geneId;
}

bool Gene::getIsPosStrand()
{
    return isPosStrand;
}

void Gene::setWidth( float newWidth )
{
    width = newWidth;
    geneInfo->setPos( boundingRect().x() + (boundingRect().x()+width)/2.0, boundingRect().y() );
}

void Gene::setHeight( float newHeight )
{
    height = newHeight;
}

//-------------------------INTERACTION FUNCTIONS----------------------

//this slot picks up hover enter events
//and signals other linked genes to be highlighted
void Gene::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
   emit( hoverEnterOverGeneSignal() );//when hovering over this gene- emit signal to other genes judged to be linked
   geneInfo->setVisible(true);
   changeAfterHoverEnter();//this is where the appearance of the gene changes
}

//this function changes the appearance of the gene after being hovered over
void Gene::changeAfterHoverEnter()
{
    colorToDraw->setRgb( highlightedColor->red(), highlightedColor->green(), highlightedColor->blue(), highlightedColor->alpha() ); //draw the highlighted color -- turning off so I can keep color continuity
    //backgroundColor->setRgb( highlightedColor->red(), highlightedColor->green(), highlightedColor->blue(), 125 );
    setTransformOriginPoint( width/2.0, height/2.0 ); //transform in the middle- because pos right now is not centered
    setScale( 1.1 );//make it slightly larger- this might setup a distortion though...
    hovering = true;
    QRectF bRect = boundingRect();
    update(bRect.x()-500, bRect.y()-500, bRect.width()+1000, bRect.height()+1000 );//must call update for change to go through
}

//when mouse not hovering- must call 'hover leave' so that it is drawn in the default style
void Gene::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
   emit( hoverLeaveOverGeneSignal() );//signal other linked genes to not get highlighted
   geneInfo->setVisible(false);
   changeAfterHoverLeave(); // change apparance to default
}

//when not hovering, or highlighted- draw normally
void Gene::changeAfterHoverLeave()
{
    if( !selected ) //if it isn't selected, then change back to user given color
        colorToDraw->setRgb( userGivenColor->red(), userGivenColor->green(), userGivenColor->blue(), userGivenColor->alpha() ); //draw the highlighted color -- turning off so I can keep color continuity

    //backgroundColor->setRgb( parent->backgroundColor.red(), parent->backgroundColor.green(), parent->backgroundColor.blue(),parent->backgroundColor.alpha() );
    setTransformOriginPoint( width/2.0, height/2.0 );
    setScale( 1.0 );
    hovering = false;
    update();
}

//for when a linked gene is being hovered over- so that this gene is changed in appearance
//but doesn't signal other genes- would be a duplicate signal
void Gene::hoverEnterOverGeneSlot()
{
    changeAfterHoverEnter();
}

//see above
void Gene::hoverLeaveOverGeneSlot()
{
    changeAfterHoverLeave();
}

void Gene::geneSelectedSlot()
{
    selected = !selected;
    for(int i = 0; i < attributes.size(); i++)
    {
        if( attributes[i]->getAttributeName().compare("GeneID") == 0)
            parent->setSelectedGene( attributes[i]->getValue() );
    }
    parent->setSelectedCluster(geneId);//tell the parent that this cluster has been selected
    if( selected )
        colorToDraw->setRgb( highlightedColor->red(), highlightedColor->green(), highlightedColor->blue(), highlightedColor->alpha() ); //draw the highlighted color -- turning off so I can keep color continuity
    else
        colorToDraw->setRgb( userGivenColor->red(), userGivenColor->green(), userGivenColor->blue(), userGivenColor->alpha() ); //draw the highlighted color -- turning off so I can keep color continuity

}

//changes the color of the gene
void Gene::changeGeneColorSlot(QColor c)
{
    colorToDraw->setRgb( c.red(), c.green(), c.blue(), c.alpha() );
    userGivenColor->setRgb( c.red(), c.green(), c.blue(), c.alpha());

    qDebug() << "gene color change slot" << endl;
}

//if control click- other contigs that contain this gene, align with it
void Gene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << " click" << endl;
    if ( event->button() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier)
    {
        qDebug() << "control click" << endl;
        QPointF loc = QPointF(0,0);
        QPointF distToMove = mapToScene( loc );//mapToParent( loc );
        emit( alignWithThisGene( distToMove.x(), isPosStrand ) );

        int direction = 3;
        if( isPosStrand )
            direction = 1;

        emit( alignmentEvent( geneId, mapToScene(loc), direction ));
    }
    else if( event->button() == Qt::LeftButton && ( event->modifiers() == Qt::AltModifier || event->modifiers() == Qt::ShiftModifier) )
    {
        QColorDialog *colorDialog = new QColorDialog;
        colorDialog->setVisible(false);

//        QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(0, Qt::Window);
//        proxy->setWidget(colorDialog);

        QColor newColor = colorDialog->getColor();
        userGivenColor->setRgb( newColor.red(), newColor.green(), newColor.blue(), newColor.alpha() );//don't think i need this
        colorToDraw->setRgb( newColor.red(), newColor.green(), newColor.blue(), newColor.alpha() );

        emit( changeGeneColorSignal(newColor));
        qDebug() << newColor.red() << " " << newColor.green() << " " << newColor.blue() << " " << newColor.alpha() << endl;
        update();
    }
    else // draw gene as 'selected' and signal other genes to draw the same way
    {
        selected = !selected;
        emit( geneSelectedSignal() );
        if( selected )
            colorToDraw->setRgb( highlightedColor->red(), highlightedColor->green(), highlightedColor->blue(), highlightedColor->alpha() ); //draw the highlighted color -- turning off so I can keep color continuity
        else
            colorToDraw->setRgb( userGivenColor->red(), userGivenColor->green(), userGivenColor->blue(), userGivenColor->alpha() ); //draw the highlighted color -- turning off so I can keep color continuity
        QString id;
        for(int i = 0; i < attributes.size(); i++)
        {
            if( attributes[i]->getAttributeName().compare("GeneID") == 0 )
            {
                //id.append( attributes[i]->getValue() );
                parent->setSelectedGene( attributes[i]->getValue() );
            }
        }
        parent->setSelectedGene( id ); //tell parent that it has been selected
    }
}

//thought I could use, but I was wrong.
void Gene::keyPressEvent ( QKeyEvent * event )
{
//    if( event->text().compare("a") == 0 )
//    {
//        alignKeyPressed = true;
//    }
//    if( event->text().compare("f") == 0 )
//    {
//        flipKeyPressed = true;
//    }
//    if( event->text().compare("c") == 0 )
//    {
//        colorKeyPressed = true;
//    }

//    qDebug() << "in gene, key pressed " << endl;

}

//if need to align with a linked gene, calculate how far the contig has to move
void Gene::calculateReAlignment( float otherGenePos , bool posStrand)
{
    QPointF pt = mapToScene(0, boundingRect().height()/2.0); //mapToParent( 0, 0 );
    //parentItem()->moveBy( otherGenePos - pt.x(), 0.0 ); // move contig by the distance between this gene and linked gene
    parent->setDistToMove( QPoint( otherGenePos - pt.x(), 0.0 ));
    if( posStrand != isPosStrand )
    {
        pt = mapToParent( pt.x(), pt.y() );
        parent->setFlip( true, pt );
    }
}


//-------------------------END INTERACTION FUNCTIONS----------------------

//----------------------------DRAW FUNCTIONS-----------------------------
QRectF Gene::boundingRect() const
{
    return QRectF(0, 0, width, height);
}

QPainterPath Gene::shape() const
{
    QPainterPath path;
    path.addRect(boundingRect());
    return path;
}


void Gene::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    QRectF bRect = boundingRect();

    painter->setRenderHint(QPainter::Antialiasing);

    painter->setBrush(*colorToDraw);
    painter->setPen( Qt::NoPen );

//    if( selected )
//    {

//        QColor selectColor;
//        selectColor.setRgb( 243.0, 245.0, 0.0, 150.0 );
////        painter->setBrush( selectColor );
////        setScale(1.1);
////        painter->drawRect( boundingRect() );

////        QPen pen( *highlightedColor );
////        float h = (float)height / 5.0 ;
////        if( h < 1.0 )
////            h = 1.0;
////        pen.setWidth( 1.0 );
////        painter->setPen( pen );

//        QLinearGradient gradient;
//        gradient.setColorAt(boundingRect().y(), QColor::fromRgb(userGivenColor->red(), userGivenColor->green(), userGivenColor->blue()));
//        gradient.setColorAt(boundingRect().height(), QColor::fromRgb(selectColor.red(), selectColor.green(), selectColor.blue()));

//        QBrush brush(gradient);
//        painter->setBrush(brush);

//    }
//    else
//    {
//        painter->setPen( Qt::NoPen );
//        setScale(1.0);
//    }


    bool drawForward = ( isPosStrand && parent->minNT < parent->maxNT ) || ( !isPosStrand && parent->minNT > parent->maxNT );

    if( drawForward )//isPosStrand )//draw arrow to the right if positive strand
    {
        float triangleDiff =  -bRect.width()*.25;//how far to draw rect before hitting triangle
        if( bRect.width()*.25 < 4 )
            triangleDiff = -(bRect.width());//if small gene- just draw triangle
        if( bRect.width() > 12 )
            triangleDiff = -12.0;

        bRect.adjust(0, .25*bRect.height(), triangleDiff, -.25*bRect.height()); //adjust bounding rect
        painter->drawRect(bRect);

        //draw triangle
        bRect = boundingRect();
        QPointF p1( bRect.x()+bRect.width(), bRect.y()+bRect.height()/2 );
        QPointF p2( bRect.x()+bRect.width()+triangleDiff, bRect.y());
        QPointF p3( bRect.x()+bRect.width()+triangleDiff, bRect.y()+bRect.height() );
        QPolygonF poly;
        poly << p1 << p2 << p3;
        painter->drawPolygon(poly);

        //drawArrow( bRect, p1, p2, p3, colorToDraw );
    }
    else //draw arrow to the left
    {
        float triangleDiff =  bRect.width()*.25;
        if( bRect.width()*.25 < 4 )
            triangleDiff = (bRect.width());
        if( bRect.width() > 12 )
            triangleDiff = 12.0;

        bRect.adjust(triangleDiff, .25*bRect.height(), 0, -.25*bRect.height());
        painter->drawRect(bRect);

        bRect = boundingRect();
        QPointF p1( bRect.x(), bRect.y()+bRect.height()/2 );
        QPointF p2( bRect.x()+triangleDiff, bRect.y());
        QPointF p3( bRect.x()+triangleDiff, bRect.y()+bRect.height() );
        QPolygonF poly;
        poly << p1 << p2 << p3;
        painter->drawPolygon(poly);
    }

    //make sure gene label drawn in the correct orientation
    //ok, this kinda sucks ... because not very easy to translate to different situations
    //but, I'll have to come up with something better later
    QPointF contigPos = parentItem()->parentItem()->pos();//parent contigs position in the browser
    QRectF browserBoundingRect = parentItem()->parentItem()->parentItem()->boundingRect();
    if( contigPos.y() < browserBoundingRect.y()+geneInfo->boundingRect().height())//50 )
    {
        geneInfo->changeDirection( 2 );
        geneInfo->setPos( (boundingRect().x() + width)/2.0, boundingRect().y()+boundingRect().height() );
    }
    else
    {
       geneInfo->changeDirection( 0 );
       geneInfo->setPos( (boundingRect().x()+width)/2.0, boundingRect().y() );

    }
}

//void Gene::drawArrow( const QRectF& body, const QPointF& p1, const QPointF& p2, const QPointF& p3, const QColor& color )
//{
//    painter->setBrush( color );
//    painter->setPen( Qt::NoPen );

//    painter->drawRect(bRect);

//    QPolygonF poly;
//    poly << p1 << p2 << p3;
//    painter->drawPolygon(poly);
//}


//----------------------------END DRAW FUNCTIONS-----------------------------
